'use strict';

const Olt = require("./OLT");
const snmp = require('net-snmp');
const common = require('../common')
const net = require('net');
class XDOLT extends Olt {
  constructor(options) {
    super(options);
  }
  static getVersion(str) {
    let reg = /(C\d{3}).*(V\d.\d.\d)/;
    if (reg.test(str)) {
      let arr = reg.exec(str);
      return arr[1] + " " + arr[2];
    } else {
      return str;
    }
  }
  static HexStrToBinStr(str) {
    var list = str.split("");
    let result = [];
    for (var i = 0; i < list.length; i++) {
      let a = parseInt(list[i], 16);
      let b = a.toString(2);
      let c = '0000' + b;
      let d = c.substr(c.length - 4, 4);
      result.push(d);
    }
    return result.join('');
  }
  async getOltInformation(){
    return new Promise((resolve, reject) => {
        let olt = {
          systemName: "",
          serialNumber: "",
          hardwareVersion: "",
          softwareVersion: "",
          macAddress: "",
        //   softwareCreatedTime: "",
          systemTime: "",
          runningTime: "",
          cpuUsage: 0,
          memoryUsage: 0,
        //   licenseLimit: "",
        //   licenseTime: "",
        };
        let oids = [
          "1.3.6.1.4.1.37950.1.1.5.10.12.5.1.0", //systemName
          "1.3.6.1.4.1.37950.1.1.5.10.12.5.11.0", //serial number
          "1.3.6.1.4.1.37950.1.1.5.10.12.5.5.0", //hardversion
          "1.3.6.1.4.1.37950.1.1.5.10.12.5.4.0", //softwareversion
          "1.3.6.1.4.1.37950.1.1.5.10.12.5.7.0", //macAddress
          // '1.3.6.1.4.1.37950.1.1.5.10.12.5.14.0', //software created time
          "1.3.6.1.4.1.37950.1.1.5.10.12.5.10.0", //system time
          "1.3.6.1.4.1.37950.1.1.5.10.12.5.8.0", //running time
          "1.3.6.1.4.1.37950.1.1.5.10.12.3.0", //cpu
          "1.3.6.1.4.1.37950.1.1.5.10.12.4.0", //memory
          // '1.3.6.1.4.1.37950.1.1.5.10.12.5.12.0', //license limit
          // '1.3.6.1.4.1.37950.1.1.5.10.12.5.13.0' //license time
        ];
        let session = snmp.createSession(
          this.options.ip,
          this.options.community,
          { version: 1 }
        );
        session.get(oids, function (error, varbinds) {
          if (error) {
            reject(error);
          } else {
            for (let i = 0; i < varbinds.length; i++) {
              if (!snmp.isVarbindError(varbinds[i])) {
                if (varbinds[i].oid == oids[0]) {
                  olt.systemName = varbinds[i].value.toString();
                }
                if (varbinds[i].oid == oids[1]) {
                  olt.serialNumber = varbinds[i].value.toString();
                }
                if (varbinds[i].oid == oids[2]) {
                  let str = varbinds[i].value.toString();
                  olt.hardwareVersion = XDOLT.getVersion(str);
                }
                if (varbinds[i].oid == oids[3]) {
                  olt.softwareVersion = varbinds[i].value.toString();
                }
                if (varbinds[i].oid == oids[4]) {
                  olt.macAddress = varbinds[i].value.toString();
                }
                // if (varbinds[i].oid == oids[5]) {
                //   olt.softwareCreatedTime = varbinds[i].value.toString();
                // }
                if (varbinds[i].oid == oids[6]) {
                  olt.systemTime = varbinds[i].value.toString();
                }
                if (varbinds[i].oid == oids[7]) {
                  olt.runningTime = varbinds[i].value.toString();
                }
                if (varbinds[i].oid == oids[8]) {
                  olt.cpuUsage = varbinds[i].value;
                }
                if (varbinds[i].oid == oids[9]) {
                  olt.memoryUsage = varbinds[i].value;
                }
                // if (varbinds[i].oid == oids[10]) {
                //   olt.licenseLimit = varbinds[i].value.toString();
                // }
                // if (varbinds[i].oid == oids[11]) {
                //   olt.licenseTime = varbinds[i].value.toString();
                // }
              }
            }
            resolve(olt);
          }
          session.close();
        });
      });
  }
  async XDTestConnection(){
    return new Promise((resolve, reject) => {
        let username = this.options.username;
        let password = this.options.password;
        let socketclient = net.createConnection({
          host: this.options.ip,
          port: this.options.tPort,
        }, function () {
        })
        let step = 0;
        socketclient.on("data", function (data) {
          let info = data.toString();
          if (step == 2) {
            if (info.indexOf('Login Failed') != -1) {
              socketclient.destroy();
              resolve(false);
            } else {
              socketclient.destroy();
              resolve(true);
            }
          }
          if (info.indexOf('Login') != -1) {
            step++;
            socketclient.write(`${username}\r\n`);
          }
          if (info.indexOf('Password') != -1) {
            step++;
            socketclient.write(`${password}\r\n`);
          }
        });
    
        socketclient.on("close", function () {
        });
    
        socketclient.on("error", function (err) {
          resolve(false);
        });
      })
  }
  async GetCommunity_XD(me){
    return new Promise(async (resolve, reject) => {
        let addr = this.options.ip + ":" + this.options.tPort;
  
        //组装模板变量
        let view = {
          username: this.options.username,
          password: this.options.password,
          prompt: this.options.systemName,
          ManagementPassword: this.options.managementPassword,
        };
        try {
          let resultArr = await common.run_EX(addr, {
            oltType: "OPTICTIMES",
            mountPoint: "GET_COMMUNITY",
            oltHardVersion: "NONE",
            view,
          },null,me);
          let result = [];
          let msg = resultArr[0].split('\n')
          msg.pop()
          for(var i=2;i<msg.length;i++){
              result.push(msg[i].split('\r')[0].trim())
          }
          resolve(result)
        } catch (error) {
          resolve(null);
        }
      });
  }
  async DeleteCommunity_XD(CommunityArr,me){
    return new Promise(async (resolve, reject) => {
        let addr = this.options.ip + ":" + this.options.tPort;
        //组装模板变量
        let view = {
          username: this.options.username,
          password: this.options.password,
          prompt: this.options.systemName,
          ManagementPassword: this.options.managementPassword,
          CommunityArr: CommunityArr,
        };
        try {
          let resultArr = await common.run_EX(addr, {
            oltType: "OPTICTIMES",
            mountPoint: "DELETE_COMMUNITY",
            oltHardVersion: "NONE",
            view,
          },null,me);
          resolve(true);
        } catch (error) {
          resolve(false);
        }
      });
  }
  async SetCommunity_XD(rocommunity, rwcommunity,me){
    return new Promise(async (resolve, reject) => {
        let addr = this.options.ip + ":" + this.options.tPort;
  
        //组装模板变量
        let view = {
          username: this.options.username,
          password: this.options.password,
          prompt: this.options.systemName,
          ManagementPassword: this.options.managementPassword,
          rwcommunity: rwcommunity,
          rocommunity: rocommunity,
        };
        try {
          let resultArr = await common.run_EX(addr, {
            oltType: "OPTICTIMES",
            mountPoint: "MODIFY_COMMUNITY",
            oltHardVersion: "NONE",
            view,
          },null,me);
          resolve(true);
        } catch (error) {
          resolve(false);
        }
      });
  }
  async saveOlt(oltHardVersion,me){
    return new Promise(async (resolve, reject) => {
      let addr = this.options.ip + ":" + this.options.tPort
      let view = {
          username: this.options.username,
          password: this.options.password,
          prompt: this.options.systemName,
          ManagementPassword: this.options.managementPassword,
      }
      try {
        let resultArr = await common.run_EX(addr, {
            oltType: 'OPTICTIMES',
            mountPoint: 'SAVE',
            oltHardVersion,
            view},null,me)
        resolve(true)
      } catch (error) {
        reject(error)
      }
    });
  }
  async getPonPortList() {
      var maxRepetitions = 20;
      var oid = "1.3.6.1.4.1.37950.1.1.5.10.1.2.1";
      var columns = [1,3];
      return new Promise((resolve,reject) =>{
        let session = snmp.createSession(this.options.ip, this.options.community, this.options);
        session.tableColumns(oid,columns,maxRepetitions,function(error,table){
          if (error) {
              return reject(error);
          } else {
              return resolve(table);
          }
        })
      })
  }
  async getUplinkPortInfo() {
    var maxRepetitions = 20;
    var oid1 = "1.3.6.1.4.1.37950.1.1.5.10.1.1.1"
    var columns1 = [1,4,18]
    var oid2 = "1.3.6.1.4.1.37950.1.1.5.10.1.1.3";
    var columns2 = [2,3];
    let p1 = new Promise((resolve,reject) =>{
      let session = snmp.createSession(this.options.ip, this.options.community, this.options);
      session.tableColumns(oid1,columns1,maxRepetitions,function(error,table){
        if (error) {
            return reject(error);
        } else {
            return resolve(table);
        }
      })
    })
    let p2 = new Promise((resolve,reject) =>{
      let session = snmp.createSession(this.options.ip, this.options.community, this.options);
      session.tableColumns(oid2,columns2,maxRepetitions,function(error,table){
        if (error) {
            return reject(error);
        } else {
            return resolve(table);
        }
      })
    })
    return Promise.all([p1, p2]);
  }
  async getUplinkVlan(list,oltHardVersion,me){
    return new Promise(async (resolve, reject) => {
      let addr = this.options.ip + ":" + this.options.tPort;
      let view = {
          username: this.options.username,
          password: this.options.password,
          prompt: this.options.systemName,
          ManagementPassword: this.options.managementPassword,
          list
      }
      try {
          let resultArr = await common.run_EX(addr, {
              oltType: "OPTICTIMES",
              mountPoint: "GET_UPLINK_VLAN",
              oltHardVersion,
              view,
          },null,me);
          resultArr.shift()
          resultArr.forEach((item,index) =>{
            // let untag = item.substring(item.indexOf('Untagged VLAN ID:')+17,item.indexOf('Tagged VLAN ID  :')).trim().replace(/\s{2,}/g,"|").split("|").toString()
            // list[index].UnTagvlan = untag
            let result = []
            let tagArr = item.substring(item.indexOf('Tagged VLAN ID  :')+17,item.indexOf('Last 300 seconds input:')).trim().replace(/\s{2,}/g,"|").split("|")
            tagArr.forEach(item => {
              if(item != "1"){
                result.push(item)
              }
            })
            list[index].Tagvlan = result.toString()
          })
          resolve(list)
      } catch (error) {
        reject(error);
      }
    })
  }
  async getUplinkAdminstatusAndUnTagVlan(port){
    var maxRepetitions = 20;
    var oid1 = "1.3.6.1.4.1.37950.1.1.5.10.1.1.1"
    var columns1 = [4,18]
    return new Promise((resolve,reject) =>{
      let session = snmp.createSession(this.options.ip, this.options.community, this.options);
      session.tableColumns(oid1,columns1,maxRepetitions,function(error,table){
        if (error) {
            return reject(error);
        } else {
            return resolve(table[port]);
        }
      })
    })
  }
  async getUplinkConfig(res,port,oltHardVersion,me){
    let temp = Object.create(null)
    if(res[4].toString() == "1"){
      temp.AdminStatus = 1
    }else{
      temp.AdminStatus = 2
    }
    if(res[18].toString() != "1"){
      temp.UnTagvlan = res[18]
    }else{
      temp.UnTagvlan = ""
    }
    return new Promise(async (resolve, reject) => {
      let addr = this.options.ip + ":" + this.options.tPort;
      let view = {
          username: this.options.username,
          password: this.options.password,
          prompt: this.options.systemName,
          ManagementPassword: this.options.managementPassword,
          port
      }
      try {
          let resultArr = await common.run_EX(addr, {
              oltType: "OPTICTIMES",
              mountPoint: "GET_UPLINK_TAGVLAN",
              oltHardVersion,
              view,
          },null,me);
          let result = []
          let tagArr = resultArr[0].substring(resultArr[0].indexOf('Tagged VLAN ID  :')+17,resultArr[0].indexOf('Last 300 seconds input:')).trim().replace(/\s{2,}/g,"|").split("|")
          tagArr.forEach(item => {
            if(item != "1"){
              result.push(item)
            }
          })
          temp.Tagvlan = result.toString()
          resolve(temp)
      } catch (error) {
        reject(error);
      }
    })
  }
  async setUplink(portID,adminStatus,addvlan,UnTagvlan,oldUnTagvlan,removevlan,oltHardVersion,me){
    if(adminStatus == 1){
      var type = "no shutdown"
    }else if(adminStatus == 2){
      var type = "shutdown"
    }
    return new Promise(async (resolve, reject) => {
      let addr = this.options.ip + ":" + this.options.tPort;
      let view = {
          username: this.options.username,
          password: this.options.password,
          prompt: this.options.systemName,
          ManagementPassword: this.options.managementPassword,
          portID,
          type,
          addvlan,
          UnTagvlan,
          oldUnTagvlan,
          removevlan
      }
      try {
          let resultArr = await common.run_EX(addr, {
              oltType: "OPTICTIMES",
              mountPoint: "SET_UPLINK",
              oltHardVersion,
              view,
          },null,me);
          resolve(true)
      } catch (error) {
        reject(error);
      }
    })
  }
  async getVlanTable() {
    return new Promise((resolve, reject) => {
      let vlanArray = [];
      let session = snmp.createSession(
        this.options.ip,
        this.options.community,
        { version: 1 }
      );
      session.table("1.3.6.1.4.1.37950.1.1.5.10.2.6", function (error, table) {
        if (error) {
          return reject(error);
        } else {
          for (let i in table) {
            vlanArray.push({
              VlanID: table[i][1].toString(),
              Memo: table[i][6].toString(),
              VlanTagPort: XDOLT.HexStrToBinStr(table[i][3].toString()),
              VlanUntagPort: XDOLT.HexStrToBinStr(table[i][4].toString()),
              vlanRowStatus: table[i][5].toString(),
            });
          }
          return resolve(vlanArray);
        }
      });
    });
  }
  async getMacTable() {
    return new Promise((resolve, reject) => {
      let arr = [];
      let session = snmp.createSession(
        this.options.ip,
        this.options.community,
        { version: 1 }
      );
      session.table("1.3.6.1.4.1.37950.1.1.5.10.3.2", function (error, table) {
        if (error) {
          return reject(error);
        } else {
          for (let i in table) {
            let macHex = table[i][3].toString("hex");
            let macArr = macHex.split("");
            let arr1 = [];
            for (let j = 0; j < macArr.length; j++) {
              if (j % 2 == 0 && j > 0) {
                arr1.push("-");
                arr1.push(macArr[j]);
              } else {
                arr1.push(macArr[j]);
              }
            }
            let macStr = arr1.join("");
            arr.push({
              VlanID: table[i][2].toString(),
              Mac: macStr.toString(),
              Type: table[i][4].toString(),
              PhysicalPort: table[i][5].toString(),
            });
          }
          return resolve(arr);
        }
      });
    });
  }
  async setVlans_XD(vlanStart,vlanEnd,oltHardVersion,me){
    return new Promise(async (resolve, reject) => {
        let addr = this.options.ip + ":" + this.options.tPort;
        let view = {
            username: this.options.username,
            password: this.options.password,
            prompt: this.options.systemName,
            ManagementPassword: this.options.managementPassword,
            vlanStart: vlanStart,
            vlanEnd: vlanEnd
        }
        try {
            let resultArr = await common.run_EX(addr, {
                oltType: "OPTICTIMES",
                mountPoint: "SET_VLAN",
                oltHardVersion,
                view,
            },null,me);
            resolve(true)
        } catch (error) {
          reject(error);
        }
    })
  }
  async deleteVlan_XD(vlanID,oltHardVersion,me){
    return new Promise(async (resolve, reject) => {
        let addr = this.options.ip + ":" + this.options.tPort;
        let view = {
            username: this.options.username,
            password: this.options.password,
            prompt: this.options.systemName,
            ManagementPassword: this.options.managementPassword,
            vlanID,
        }
        try {
            let resultArr = await common.run_EX(addr, {
                oltType: "OPTICTIMES",
                mountPoint: "DELETE_VLAN",
                oltHardVersion,
                view,
            },null,me);
            resolve(true)
        } catch (error) {
          reject(error);
        }
    })
  }
  async getonufind_XD(){
    return new Promise((resolve, reject) => {
        let arr = [];
        let session = snmp.createSession(
          this.options.ip,
          this.options.community,
          { version: 1 }
        );
        session.table("1.3.6.1.4.1.37950.1.1.6.1.2.1", function (error, table) {
          if (error) {
            return reject(error);
          } else {
            for (let i in table) {
              arr.push({
                PONindex: table[i][1].toString(),
                SN:table[i][3].toString(),
                state:table[i][4].toString()
              });
            }
            return resolve(arr);
          }
        });
      });
  }
  async getOnuProfileList(){
    return new Promise((resolve, reject) => {
      let arr = [];
      let session = snmp.createSession(
        this.options.ip,
        this.options.community,
        { version: 1 }
      );
      session.table("1.3.6.1.4.1.37950.1.1.6.2.2.1", function (error, table) {
        if (error) {
          return reject(error);
        } else {
          for (let i in table) {
            arr.push({
              PID: table[i][1].toString(),
              Pname:table[i][2].toString(),
            });
          }
          return resolve(arr);
        }
      });
    });
  }
  async setONU(ONUindex,PONindex,ONUProfileName,mode,vlan,uplink,down,name,sn,oltHardVersion,me){
    return new Promise(async (resolve,reject) =>{
      let addr = this.options.ip + ":" + this.options.tPort;
      let view = {
        username:this.options.username,
        password:this.options.password,
        prompt: this.options.systemName,
        ManagementPassword:this.options.managementPassword,
        ONUindex,
        PONindex,
        ONUProfileName,
        mode,
        vlan,
        uplink,
        down,
        name,
        sn,
      }
      try {
        let fn = function (msg) {
          if (msg.indexOf(`onu profile ${ONUProfileName} not found or it's not commited`) != -1) {
            return {result: false,message: `onu profile ${ONUProfileName} not found or it's not commited`};
          } else if (msg.indexOf("onu ID is existed") != -1) {
            return { result: false, message: "onu ID is existed" };
          } else if (msg.indexOf("GPON ONU sn already exists") != -1) {
            return { result: false, message: "GPON ONU sn already exists" };
          } else if (msg.indexOf(`profile traffic ${down} is not exist`) != -1) {
            return {result: false,message: `profile traffic ${down} is not exist`};
          } else if (msg.indexOf(`profile traffic ${uplink} is not exist`) != -1) {
            return {result: false,message: `profile traffic ${uplink} is not exist`};
          } else {
            return { result: true };
          }
        };
        let resultArr = await common.run_EX(
          addr,
          {
            oltType: "OPTICTIMES",
            mountPoint: "CREATE_ONUFIND",
            oltHardVersion,
            view,
          },fn,me);
          if (resultArr.length != 0) {
            resolve(resultArr);
          } else {
            resolve(true);
          }
      } catch (error) {
        reject(error);
      }
    })
  }
  async deleteONU(PONindex,ONUindex,oltHardVersion,me){
    return new Promise(async (resolve,reject) =>{
      let addr = this.options.ip + ":" + this.options.tPort;
      let view = {
        username:this.options.username,
        password:this.options.password,
        prompt: this.options.systemName,
        ManagementPassword:this.options.managementPassword,
        ONUindex,
        PONindex,
      }
      try {
        let resultArr = await common.run_EX(
          addr,
          {
            oltType: "OPTICTIMES",
            mountPoint: "DELETE_ONU",
            oltHardVersion,
            view,
          },null,me);
          resolve(true)
      } catch (error) {
        reject(error);
      }
    })
  }
  async getOnuList(){
    return new Promise((resolve, reject) => {
      let arr = [];
      let session = snmp.createSession(
        this.options.ip,
        this.options.community,
        { version: 1 }
      );
      session.table("1.3.6.1.4.1.37950.1.1.6.1.1.1", function (error, table) {
        if (error) {
          return reject(error);
        } else {
          for (let i in table) {
            arr.push({
              PONindex: table[i][1].toString(),
              ONUindex:table[i][2].toString(),
              state:table[i][5].toString(),
            });
          }
          return resolve(arr);
        }
      });
    });
  }
  async getONUSN(){
    return new Promise((resolve, reject) => {
      let arr = [];
      let session = snmp.createSession(
        this.options.ip,
        this.options.community,
        { version: 1 }
      );
      session.table("1.3.6.1.4.1.37950.1.1.6.1.1.2", function (error, table) {
        if (error) {
          return reject(error);
        } else {
          for (let i in table) {
            arr.push({
              PONindex: table[i][1].toString(),
              ONUindex:table[i][2].toString(),
              SN:table[i][5].toString(),
            });
          }
          return resolve(arr);
        }
      });
    });
  }
  async getONUDetailInfo(){
    return new Promise((resolve, reject) => {
      let arr = [];
      let session = snmp.createSession(
        this.options.ip,
        this.options.community,
        { version: 1 }
      );
      session.table("1.3.6.1.4.1.37950.1.1.6.1.1.4", function (error, table) {
        if (error) {
          return reject(error);
        } else {
          for (let i in table) {
            arr.push({
              PONindex: table[i][1].toString(),
              ONUindex:table[i][2].toString(),
              ONUname:table[i][24].toString(),
            });
          }
          return resolve(arr);
        }
      });
    });
  }
}

module.exports = XDOLT;
